package com.codecoord.spring.core;

import com.codecoord.spring.config.MySpringConfiguration;
import com.codecoord.spring.domain.Person;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.function.Supplier;

/**
 * 基于注解上下文加载测试
 *
 * @author tianxincoord@163.com
 * @since 2022/2/15
 */
@SuppressWarnings("all")
public class AnnotationApplicationContextTest {
	/**
	 * - 注册Bean {@link AnnotatedBeanDefinitionReader#doRegisterBean(Class, String, Class[], Supplier, BeanDefinitionCustomizer[])}
	 * {@link DefaultListableBeanFactory#registerBeanDefinition(String, BeanDefinition)}
	 * org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition(java.lang.String, org.springframework.beans.factory.config.BeanDefinition)
	 * org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory)
	 * 前置只注册了一个扫描Bean，剩下的Bean是通过Bean工厂后置处理器进行递归包扫描注入，
	 * org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List)
	 * org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors(java.util.Collection, org.springframework.beans.factory.support.BeanDefinitionRegistry)
	 * 递归扫描注解类的入口
	 * org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions(org.springframework.beans.factory.support.BeanDefinitionRegistry)
	 * org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set)
	 * org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass(org.springframework.context.annotation.ConfigurationClass)
	 * org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass(org.springframework.context.annotation.ConfigurationClass, org.springframework.context.annotation.ConfigurationClassParser.SourceClass)
	 * org.springframework.context.annotation.ComponentScanAnnotationParser#parse(org.springframework.core.annotation.AnnotationAttributes, java.lang.String)
	 * 递归扫描
	 * org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan(java.lang.String...)
	 * 给定指定包扫描符合条件的组件
	 * org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#findCandidateComponents(java.lang.String)
	 * 扫描所有字节码的核心
	 * org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents(java.lang.String)
	 * 扫描原理：
	 * 1、获取到指定路径下的所有.class文件，"classpath*:com/codecoord/spring/**\/*.class"
	 * 2、然后逐一解析字节码文件，例如加了组件注解的就加入等等日常使用规则的
	 *
	 * 属性填充：
	 * 1、通过getBean，当Bean不存在将会被实例化
	 * org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons()
	 * org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean(java.lang.String, java.lang.Class, java.lang.Object[], boolean)
	 * org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization(org.springframework.beans.factory.config.ConfigurableListableBeanFactory)
	 * 2、实例化Bean核心，被依赖的Bean会先加载
	 * org.springframework.beans.factory.support.DefaultListableBeanFactory#getBean(java.lang.Class, java.lang.Object...)
	 * 3、创建单例Bean
	 * org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory)
	 * 4、创建Bean核心，前置Bean处理器等
	 * org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
	 * org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition)
	 * 5、创建Bean实例核心方法，创建实例、属性填充等
	 * {@link AbstractAutowireCapableBeanFactory#doCreateBean(String, RootBeanDefinition, Object[])}
	 * {@link AbstractAutowireCapableBeanFactory#createBeanInstance(String, RootBeanDefinition, Object[])}
	 * - 确定构造方法
	 * {@link AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors(Class, String)}
	 * - 应用InstantiationAwareBeanPostProcessor后置处理器
	 * {@link AbstractAutowireCapableBeanFactory#populateBean(String, RootBeanDefinition, BeanWrapper)}
	 * {@link AbstractAutowireCapableBeanFactory#applyPropertyValues(String, BeanDefinition, BeanWrapper, PropertyValues)}
	 * - 真正初始化Bean，在真正初始化Bean前后应用applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization
	 * - 所以BeanPostProcessor的作用时机在于前置Bean组装好开始实例化的时候
	 * - 应用顺序如下
	 * 	- Bean前置处理器：applyBeanPostProcessorsBeforeInitialization
	 * 	- InitializingBean处理：{@link AbstractAutowireCapableBeanFactory#invokeInitMethods(String, Object, RootBeanDefinition)}
	 *  - Bean后置处理器：applyBeanPostProcessorsAfterInitialization
	 * {@link AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)}
	 * - 处理自动注入就是判断是否含有指定注册，根据类型从实例池中查找符合条件的Bean:AutowiredAnnotationBeanPostProcessor
	 *
	 * Bean属性自动注入
	 *
	 *
	 * 循环依赖：
	 * {@link }
	 */
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfiguration.class);
		Person person = context.getBean("person", Person.class);
		System.out.println("person = " + person);
		context.close();
	}
}
